﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace SRTMImport
{
    class Program
    {
        private static IDBConnection db;
        private const string BasePath = @"G:\Srtm\";

        static void Main(string[] args)
        {
            db = new DBConnection(Constants.DefaultConnectionString);

            foreach (var fileName in Directory.EnumerateFiles(BasePath))
            {
                string filePath = Path.Combine(BasePath, fileName);

                ImportSRTMFile(filePath);
            }
        }

        private static void ImportSRTMFile(string filePath)
        {
            var fileName = Path.GetFileNameWithoutExtension(filePath);
            float bottomLat;
            float leftLon;

            string latNS  = fileName.Substring(0, 1);
            string latStr = fileName.Substring(1, 2);
            string lonWE  = fileName.Substring(3, 1);
            string lonStr = fileName.Substring(4, 3);

            bottomLat = float.Parse(latStr);
            leftLon = float.Parse(lonStr);

            if(latNS == "S")
                bottomLat *= -1.0f;
            if (lonWE == "S")
                leftLon *= -1.0f;

            using (var file = File.OpenRead(filePath))
            {
                using (var reader = new BinaryReader(file))
                {
                    ImportSRTMData(bottomLat, leftLon, reader);
                }
            }
        }

        private static void ImportSRTMData(float bottomLat, float leftLon, BinaryReader reader)
        {
            const float degPerCell = 3.0f * (1.0f / (60.0f * 60.0f));
            
            float lon = leftLon;
            float lat;
            int cellNr = 0;
            int row = 0;
            int col = 0;
            while (true)
            {
                cellNr++;
                col++;
                if (col > 1201)
                {
                    row++;
                    col = 1;
                    lon = leftLon;
                }
                lat = bottomLat + 1.0f - (1.0f * (float)row) / 1200.0f;

                try
                {
                    byte b1 = reader.ReadByte();
                    byte b2 = reader.ReadByte();

                    // our little big endian converter
                    int height = b1 * 256 + b2;
                    if (b1 >= 0x80)
                        height = height - 65536;

                    // no data
                    if (height == -32768)
                        continue;

                    // error?!
                    if (height < -3000 || height > 15000)
                        throw new Exception("strange height: " + height.ToString());

                    // import height
                    ImportPoint(cellNr, lat, lon, height);

                    lon = leftLon + (1.0f * (float)col) / 1200.0f;
                }
                catch (EndOfStreamException)
                {
                    break;
                }
            }
            if (_insertQuerySelectPart.Length > 0)
            {
                string query = "INSERT INTO GeoDB.SRTM " + _insertQuerySelectPart.ToString();
                db.Execute(query);
            }
        }

        private static StringBuilder _insertQuerySelectPart = new StringBuilder();
        private static int _pointsToInsert = 0;

        private static void ImportPoint(int cellNr, float lat, float lon, int height)
        {
            int ilat = (int)(lat * 10000);
            int ilon = (int)(lon * 10000);

            _insertQuerySelectPart.AppendLine(string.Concat(_pointsToInsert == 0 ? "" : "UNION ALL ", "SELECT ", ilat.ToString(), ", ", ilon.ToString(), ", ", height.ToString()));
            _pointsToInsert++;

            if (_pointsToInsert > 50)
            {
                string query = "INSERT INTO GeoDB.SRTM " + _insertQuerySelectPart.ToString();
                db.Execute(query);

                _insertQuerySelectPart = new StringBuilder();
                _pointsToInsert = 0;
            }
        }
    }
}
